#ifndef APPLICATION_H_
#define APPLICATION_H_

/**
 * NESDroid
 * Copyright 2011 Stephen Damm (Halsafar)
 * All rights reserved.
 * shinhalsafar@gmail.com
 */

#include <jni.h>

#include "libpng/png.h"

#include "fceu_src/types.h"
#include "fceu_src/drivers/common/config.h"

#include "common.h"
#include "GraphicsDriver.h"
#include "InputHandler.h"

extern "C"
{
#include "rewind.h"
}


#define TURBO_FRAMES_TO_EMULATE 10
#define REWIND_MEMORY_SIZE 10<<21

#define FCEU_RENDER_TEXTURE_WIDTH (256.0)
#define FCEU_RENDER_TEXTURE_HEIGHT (240.0)

#define NES_ASPECT_RATIO SCREEN_4_3_ASPECT_RATIO


// PC Palette
struct pcpal {
    unsigned char r;
    unsigned char g;
    unsigned char b;
    unsigned char a;
};



enum Buttons
{
     BUTTON_INDEX_B = 0,
     BUTTON_INDEX_A = 1,
     BUTTON_INDEX_START = 2,
     BUTTON_INDEX_SELECT = 3,
     BUTTON_INDEX_REWIND = 4,
     BUTTON_INDEX_FORWARD = 5,
     BUTTON_INDEX_LEFT = 6,
     BUTTON_INDEX_UP = 7,
     BUTTON_INDEX_RIGHT = 8,
     BUTTON_INDEX_DOWN = 9,
     BUTTON_INDEX_COUNT
};

#pragma GCC visibility push(hidden)

class Application
{
public:
     Application();
     ~Application();

     int init(JNIEnv *env, const char* apkAbsolutePath);
     int initGraphics();
     int initAudioBuffers(const int sizeInSamples);
     void destroy();

     int setPaths(const char* externalStorageDir, const char* romDir,
    		 	 	 const char* stateDir, const char* sramDir,
    		 	 	 const char* cheatsDir);

     void processInput();

     int loadROM(const char* filename);
     void closeROM();

     void saveState(const int i);
     void saveStateMS();
     void loadState(const int i);
     void loadStateMS();
     void selectState(const int i);

     void step(const JNIEnv *env);
     void draw(const JNIEnv *env);

     void setAudioEnabled(const bool b);
     size_t readAudio(jshort* in, const size_t samples);
     size_t getCurrentEmuSamples() { return _ssize; }
     short* getAudioBuffer() { return _outSound; }

     void setFrameSkip(int i)
     {
          if (i < 0) i = 0;
          if (i > 9) i = 9;

          _frameSkip = i;
     }

     bool isRomLoaded() { return _romLoaded; }
     bool isInitialized() { return _initialized; }
     bool isAudioInit() { return _audioInitialized; }

     void setRewindEnabled(bool b);

     GraphicsDriver Graphics;
     InputHandler Input;
     pcpal Palette[256];
private:
     // init vars
     bool _initialized;
     bool _romLoaded;
     bool _fceuInitialized;
     bool _audioInitialized;

     // time
     double _timeStart;
     double _timeEnd;
     double _timeDelta;

     int _frameSkip;
     int _frameSkipCount;

     // paths
     char* _apkPath;
     char* _stateDir;
     char* _sramDir;
     char* _currentRom;

     // video
     GLbyte* _emuVideo;

     //audio
     short* _outSound;
     uint _bufferSize;

     // For the update step
     uint8 *_gfx;
     int32 *_sound;
     int32 _ssize;

     // for fceu input
     uint32 _JSReturn;
     void *_InputDPR;

     //rewind
     bool _rewindTouched;
     bool _rewindEnabled;
     size_t _rewindStateSize;
     state_manager_t* _rewindState;
     EMUFILE_MEMORY _memFile;
};

#pragma GCC visibility pop

#endif
